import { Controller, Post, Get, Body, Param, Query, UseGuards, Inject } from '@nestjs/common';
import { BondingCurveService } from '../services/bonding-curve.service';
import { TokenService } from '../services/token.service';
import { TransactionService } from '../services/transaction.service';
import { RealtimeGateway } from '../gateways/realtime.gateway';
import { PublicKey, Keypair } from '@solana/web3.js';
import { TransactionType } from '@prisma/client';
import bs58 from 'bs58';

@Controller('api/bonding-curve')
export class BondingCurveController {
  constructor(
    private readonly bondingCurveService: BondingCurveService,
    private readonly tokenService: TokenService,
    private readonly transactionService: TransactionService,
    private readonly realtimeGateway: RealtimeGateway
  ) {}

  /**
   * 初始化工厂合约
   */
  @Post('initialize-factory')
  async initializeFactory(@Body() dto: {
    authorityPrivateKey?: string;
  }) {
    try {
      let authorityKeypair: Keypair | undefined;
      
      if (dto.authorityPrivateKey) {
        authorityKeypair = Keypair.fromSecretKey(
          bs58.decode(dto.authorityPrivateKey)
        );
      }

      const isNewlyInitialized = await this.bondingCurveService.initializeFactoryIfNeeded(authorityKeypair);

      return {
        success: true,
        data: {
          isNewlyInitialized,
          message: isNewlyInitialized ? 'Factory initialized successfully' : 'Factory already initialized'
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 创建代币
   */
  @Post('create-token')
  async createToken(@Body() createTokenDto: {
    name: string;
    symbol: string;
    uri: string;
    creatorPrivateKey: string;
  }) {
    try {
      const creatorKeypair = Keypair.fromSecretKey(
        bs58.decode(createTokenDto.creatorPrivateKey)
      );

      const result = await this.bondingCurveService.createTokenWithBondingCurve(
        createTokenDto.name,
        createTokenDto.symbol,
        createTokenDto.uri,
        creatorKeypair
      );

      return {
        success: true,
        data: {
          tokenMint: result.tokenMint.toString(),
          transaction: result.transaction
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 购买代币
   */
  @Post('buy')
  async buyToken(@Body() buyTokenDto: {
    tokenMint: string;
    solAmount: number;
    buyerPublicKey: string;
  }) {
    try {
      const tokenMint = new PublicKey(buyTokenDto.tokenMint);
      const buyerPublicKey = new PublicKey(buyTokenDto.buyerPublicKey);

      // 首先检查代币是否存在于我们的bonding curve系统中
      try {
        await this.bondingCurveService.getTokenInfo(tokenMint);
      } catch (infoError) {
        return {
          success: false,
          error: (infoError as Error).message
        };
      }

      const result = await this.bondingCurveService.buyToken(
        tokenMint,
        buyTokenDto.solAmount,
        buyerPublicKey
      );

      // 获取更新后的价格并广播
      try {
        // 更新数据库中的价格
        await this.tokenService.updateTokenPrice(buyTokenDto.tokenMint);
        
        const newPrice = await this.bondingCurveService.getTokenPrice(tokenMint);
        const tokenInfo = await this.bondingCurveService.getTokenInfo(tokenMint);
        
        // 广播价格更新
        await this.realtimeGateway.broadcastTokenPriceUpdate(
          buyTokenDto.tokenMint,
          newPrice,
          tokenInfo.marketCap || 0
        );
      } catch (priceError) {
        console.warn('Failed to broadcast price update:', priceError);
      }

      return {
        success: true,
        data: result
      };
    } catch (error) {
      return {
        success: false,
        error: (error as Error).message
      };
    }
  }

  /**
   * 销售代币
   */
  @Post('sell')
  async sellToken(@Body() sellTokenDto: {
    tokenMint: string;
    tokenAmount: number;
    sellerPublicKey: string;
  }) {
    try {
      const tokenMint = new PublicKey(sellTokenDto.tokenMint);
      const sellerPublicKey = new PublicKey(sellTokenDto.sellerPublicKey);

      // 首先检查代币是否存在于我们的bonding curve系统中
      try {
        await this.bondingCurveService.getTokenInfo(tokenMint);
      } catch (infoError) {
        return {
          success: false,
          error: (infoError as Error).message
        };
      }

      const result = await this.bondingCurveService.sellToken(
        tokenMint,
        sellTokenDto.tokenAmount,
        sellerPublicKey
      );

      // 获取更新后的价格并广播
      try {
        // 更新数据库中的价格
        await this.tokenService.updateTokenPrice(sellTokenDto.tokenMint);
        
        const newPrice = await this.bondingCurveService.getTokenPrice(tokenMint);
        const tokenInfo = await this.bondingCurveService.getTokenInfo(tokenMint);
        
        // 广播价格更新
        await this.realtimeGateway.broadcastTokenPriceUpdate(
          sellTokenDto.tokenMint,
          newPrice,
          tokenInfo.marketCap || 0
        );
      } catch (priceError) {
        console.warn('Failed to broadcast price update:', priceError);
      }

      return {
        success: true,
        data: result
      };
    } catch (error) {
      return {
        success: false,
        error: (error as Error).message
      };
    }
  }

  /**
   * 获取代币价格
   */
  @Get('price/:tokenMint')
  async getTokenPrice(@Param('tokenMint') tokenMint: string) {
    try {
      const mint = new PublicKey(tokenMint);
      const price = await this.bondingCurveService.getTokenPrice(mint);

      return {
        success: true,
        data: {
          tokenMint,
          price
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 获取代币信息
   */
  @Get('info/:tokenMint')
  async getTokenInfo(@Param('tokenMint') tokenMint: string) {
    try {
      const mint = new PublicKey(tokenMint);
      const info = await this.bondingCurveService.getTokenInfo(mint);

      return {
        success: true,
        data: info
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 获取价格历史（用于蜡烛图）
   */
  @Get('price-history/:tokenMint')
  async getPriceHistory(
    @Param('tokenMint') tokenMint: string,
    @Query('timeframe') timeframe: string = '1h'
  ) {
    try {
      const mint = new PublicKey(tokenMint);
      const history = await this.bondingCurveService.getPriceHistory(mint, timeframe);

      return {
        success: true,
        data: {
          tokenMint,
          timeframe,
          data: history
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 记录交易
   */
  @Post('record-transaction')
  async recordTransaction(@Body() recordDto: {
    signature: string;
    type: 'BUY' | 'SELL';
    tokenMint: string;
    userPublicKey: string;
    amount: number; // SOL amount for buy, token amount for sell
    metadata?: any;
  }) {
    try {
      const transactionType = recordDto.type === 'BUY' ? TransactionType.BUY : TransactionType.SELL;
      
      // 对于买入交易，from是用户，to是联合曲线
      // 对于卖出交易，from是联合曲线，to是用户
      const transactionData = {
        from: recordDto.type === 'BUY' ? recordDto.userPublicKey : 'bonding-curve',
        to: recordDto.type === 'BUY' ? 'bonding-curve' : recordDto.userPublicKey,
        amount: recordDto.amount,
        type: transactionType,
        tokenMint: recordDto.tokenMint,
        metadata: recordDto.metadata,
      };

      const transaction = await this.transactionService.verifyAndRecordTransaction(
        recordDto.signature,
        transactionData
      );

      return {
        success: true,
        data: transaction
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 获取代币交易历史
   */
  @Get('transactions/:tokenMint')
  async getTokenTransactions(
    @Param('tokenMint') tokenMint: string,
    @Query('limit') limit?: string
  ) {
    try {
      const limitNum = limit ? parseInt(limit) : 50;
      const transactions = await this.transactionService.getTokenTransactions(tokenMint, limitNum);

      return {
        success: true,
        data: transactions
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 获取用户交易历史
   */
  @Get('user-transactions/:userPublicKey')
  async getUserTransactions(
    @Param('userPublicKey') userPublicKey: string,
    @Query('limit') limit?: string
  ) {
    try {
      const limitNum = limit ? parseInt(limit) : 50;
      const transactions = await this.transactionService.getUserTransactions(userPublicKey, limitNum);

      return {
        success: true,
        data: transactions
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
}
